﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace FCSChart.Graphical
{
    /// <summary>
    /// 竖线门
    /// </summary>
    public class LineVerticalGraphical : BaseGraphical
    {
        private double x;

        public double X
        {
            get { return x; }
            set { x = value; OnPropertyChanged("X"); }
        }

        public LineVerticalGraphical()
        {
            this.Fill = Brushes.Transparent;
        }
        public LineVerticalGraphical(LineVerticalGraphicalModel model) : base(model)
        {
            this.X = model.X;
            this.Fill = Brushes.Transparent;
            if (model.AreaNames != null && model.AreaNames.Count == 2)
            {
                Areas = model.AreaNames.Select(p => new GraphicalArea() { Name = p }).ToArray();
                Helper.AddExistedGraphicalName(this.ShortName, model.AreaNames.ToArray());
                if (model.AreaColors != null && model.AreaColors.Count == 2)
                {
                    Areas[0].DisplayColor = model.AreaColors[0];
                    Areas[1].DisplayColor = model.AreaColors[1];
                }
            }
        }
        protected override void InitName()
        {
            this.Name = "LineVertical";
            this.ShortName = "LV";
        }
        internal override void Move(double x, double y) { }
        #region 绘制
        internal override void Drawing()
        {
            if (OwnerChart == null || !OwnerChart.IsLoaded
                || OwnerChart.XAxis == null || !OwnerChart.XAxis.IsLoaded || OwnerChart.XAxis.ActualWidth == 0
                || OwnerChart.YAxis == null || !OwnerChart.YAxis.IsLoaded || OwnerChart.XAxis.ActualHeight == 0) return;
            if (GraphicalShape == null)
            {
                Binding binding = new Binding("X") { Source = this, Converter = Converters.LineVerticalDoubleToGeometryConverter.Converter, ConverterParameter = OwnerChart, Mode = BindingMode.OneWay };
                var temp = new Path() { Cursor = Cursors.Hand };
                temp.SetBinding(Path.DataProperty, binding);
                temp.SetBinding(Shape.FillProperty, new Binding("Fill") { Source = this });
                temp.SetBinding(Shape.StrokeProperty, new Binding("Stroke") { Source = this });
                temp.SetBinding(Shape.StrokeThicknessProperty, new Binding("StrokeThickness") { Source = this });
                temp.SetBinding(FrameworkElement.ContextMenuProperty, new Binding("ContextMenu") { Source = this });
                temp.Focusable = true;
                temp.MouseDown += Graphical_MouseDown;
                GraphicalShape = temp;
            }
            OnPropertyChanged("X");
            if (!IsCreateing) DrawingControl();
        }
        internal override void PanelMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (IsCreateing && sender is Panel panel)
            {
                var point = e.GetPosition(panel);
                X = OwnerChart.XAxis.GetLocationValue(point.X);
            }
        }

        internal override void PanelMouseMove(object sender, MouseEventArgs e)
        {
            if (IsCreateing && sender is Panel panel)
            {
                var point = e.GetPosition(panel);
                X = OwnerChart.XAxis.GetLocationValue(point.X);
            }
        }

        internal override void PanelMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (IsCreateing) { IsCreateing = false; }
        }
        #endregion

        #region 门控制
        private GraphicalArea[] Areas { get; set; }
        protected override void DrawingControl()
        {
            if (GraphicalShape is Path graphical && graphical.Data is PathGeometry geometry && geometry.Figures.Count == 1 && geometry.Figures[0].Segments.Count == 1)
            {
                if (Areas == null) Areas = new GraphicalArea[] { new GraphicalArea() { Name = OwnerChart.CreateNewAreaNameFunction(this) }, new GraphicalArea() { Name = OwnerChart.CreateNewAreaNameFunction(this) } };
                this.OwnerChart.AddGraphicalArea(Areas[0], Areas[1]);

                var segment = geometry.Figures[0].Segments[0] as LineSegment;
                var point = new Point(segment.Point.X, segment.Point.Y / 2);
                if (ControlShapes.Count > 0)
                {
                    if (ControlShapes[0] is Path path && path.Data is EllipseGeometry ellipse)
                        ellipse.Center = point;
                }
                else
                {
                    ControlShapes.Add(new Path() { Data = new EllipseGeometry(point, 5, 5), Cursor = Cursors.SizeWE });
                }
                Areas[0].Center = new Point(point.X / 2, point.Y);
                Areas[1].Center = new Point((OwnerChart.XAxis.ActualWidth + point.X) / 2, point.Y);
            }
        }
        protected override void Shape_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && sender is Path path && path.Data is EllipseGeometry ellipse)
            {
                var point = e.GetPosition(OwnerChart.ViewPanel);
                X = OwnerChart.XAxis.GetLocationValue(point.X);
                e.Handled = true;
                ellipse.Center = point;
            }
        }
        protected override void Shape_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            DrawingControl();
            base.Shape_MouseLeftButtonUp(sender, e);
        }
        protected override void Shape_MouseLeave(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed) DrawingControl();
            base.Shape_MouseLeave(sender, e);
        }
        #endregion
        internal override async void RefreshAreaSource(Func<object, double> xValueConverter, Func<object, double> yValueConverter)
        {
            if (Areas == null || Areas.Length != 2) return;
            if (!isCreateing && OwnerChart != null && OwnerChart.XSource != null && OwnerChart.XAxis != null)
            {
                var xSource = OwnerChart.XSource;
                var count = xSource.Count;
                var parentIndexs = OwnerChart.Indexs;
                var target = X;
                var maxDegreeOfParallelism = OwnerChart.Series == null ? 4 : OwnerChart.Series.MaxDegreeOfParallelism;
                var array = await Task.Run(() =>
                {
                    ConcurrentBag<int>[] indexsArray = new ConcurrentBag<int>[] { new ConcurrentBag<int>(), new ConcurrentBag<int>() };
                    if (parentIndexs == null)
                    {
                        var result = Parallel.For(0, count, new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (i) =>
                        {
                            var x = xValueConverter == null ? Convert.ToDouble(xSource[i]) : xValueConverter(xSource[i]);
                            if (x <= target) indexsArray[0].Add(i);
                            else indexsArray[1].Add(i);
                        });
                    }
                    else
                    {
                        var result = Parallel.ForEach(parentIndexs, new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (i) =>
                        {
                            var x = xValueConverter == null ? Convert.ToDouble(xSource[i]) : yValueConverter(xSource[i]);
                            if (x <= target) indexsArray[0].Add(i);
                            else indexsArray[1].Add(i);
                        });
                    }
                    return indexsArray;
                });
                if (Areas == null || Areas.Length != 2) return;
                this.Areas[0].InsideIndexs = array[0].ToArray();
                this.Areas[1].InsideIndexs = array[1].ToArray();
            }
            else
            {
                foreach (var area in Areas)
                {
                    area.InsideIndexs = null;
                }
            }
        }

        protected override BaseGraphicalModel GetGraphicalMode()
        {
            if (IsCreateing) return null;
            return new LineVerticalGraphicalModel()
            {
                AreaNames = this.Areas.Select(p => p.Name).ToArray(),
                AreaColors = this.Areas.Select(p => p.DisplayColor).ToArray(),
                X = this.X
            };
        }
        public override void Dispose()
        {
            base.Dispose();
            if (Areas != null)
            {
                if (this.OwnerChart != null)
                    this.OwnerChart.RemoveGraphicalArea(Areas);
                Areas = null;
            }
        }
    }

    public class LineVerticalGraphicalModel : BaseGraphicalModel
    {
        public double X { get; set; }

    }
}
